package com.cxs.shiro;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxs.exception.ShiroException;
import com.cxs.jwt.JwtUtil;
import com.cxs.jwt.Token;
import com.cxs.model.User;
import com.cxs.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.ObjectUtils;

import java.util.HashSet;
import java.util.Set;

/*
 * @Project:spring-boot-shiro-demo
 * @Author:cxs
 * @Motto:放下杂念,只为迎接明天更好的自己
 * */
public class AuthRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    @Autowired
    private JwtUtil jwtUtil;

    /**
     * 负责认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String accessToken= (String) token.getPrincipal();
        // 从jwt中解析用户
        Token parseToken = jwtUtil.parseToken(accessToken);

        if (ObjectUtils.isEmpty(parseToken)) {
            throw new ShiroException(HttpStatus.UNAUTHORIZED.value(), "用户凭证已失效");
        }
        User tokenUser = parseToken.getUser();

        // 从 AuthenticationToken 中获取当前用户
        String username = tokenUser.getUserName();
        // 查询数据库获取用户信息
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUserName,username);
        User user = userService.getOne(wrapper);
        // 用户不存在
        if (user == null) {
            throw new UnknownAccountException("用户不存在！");
        }
        /**
         * 将获取到的用户数据封装成 AuthenticationInfo 对象返回，此处封装为 SimpleAuthenticationInfo 对象。
         *  参数1. 认证的实体信息，可以是从数据库中获取到的用户实体类对象或者用户名
         *  参数2. 查询获取到的登录密码,及需要比对的凭据
         *  参数3. 当前 Realm 对象的名称，直接调用父类的 getName() 方法即可
         */
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName());
        return info;
    }

    /**
     * 负责权限
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Object principal = principals.getPrimaryPrincipal();
        User token = (User) principal;
        // 这个步骤在认证之后，principal必定不为空
        // 根据用户获取对应权限，这里就不获取了，因为权限和用户在一张表里
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission(token.getRole());
        return info;
    }
}
